package com.schedule;

import com.Mapper.SecondaryMapper.SecondaryMapper;
import com.param.Engineer.*;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Slf4j
@Component
public class TestSchedule {


    @Autowired
    private SecondaryMapper secondaryMapper;

    @GetMapping("textRemoveAll")
    public void textRemoveAll(){




        //  List<ExtractBaseInfo> baseInfoApply = secondaryMapper.SQLBaseInfo();
        // List<ExtractBaseInfo> baseInfoExtra = secondaryMapper.SQLExtBaseInfo();
        //  List<ExtractEngineeringVersions> VersionApply = secondaryMapper.SQLVersion();
        // List<ExtractEngineeringVersions> VersionExtra = secondaryMapper.SQLExtVersion();


        //  List<ExtractPicInfo> picApply = secondaryMapper.SQLPic();
        //  List<ExtractPicInfo> picExtra = secondaryMapper.SQLExtPic();
        HashSet<EngineeringDirectors> dirApply = secondaryMapper.SQLDirec();
        List<EngineeringDirectors> dirApplyList = secondaryMapper.SQLDirecList();
        HashSet<String> dirApplyID = secondaryMapper.IDSQLDirec();
        HashSet<EngineeringDirectors> dirExtra = secondaryMapper.SQLExtDirec();
        List<EngineeringDirectors> dirExtraList = secondaryMapper.SQLExtDirecList();
        HashSet<String> dirExtraID = secondaryMapper.IDSQLExtDirec();


        List<EngineeringDirectors> list = new ArrayList<>();
        log.error("TimeStart:[{}]",System.currentTimeMillis());
        for (EngineeringDirectors directors : dirExtra) {
            if (!dirApply.contains(directors)){
                list.add(directors);
            }
        }
        log.error("TimeEnd:[{}]",System.currentTimeMillis());

        //    dirExtraList.removeAll(dirApplyList);

        log.error("TimeOver:[{}]",System.currentTimeMillis());

        Set<EngineeringDirectors> collect = dirExtra.parallelStream()
                .filter(item -> !dirApply.contains(item))
                .collect(Collectors.toSet());

        log.error("TimeEnd:[{}]",System.currentTimeMillis());


        dirApplyID.removeAll(dirExtraID);



        List<String > listId = new ArrayList<>();
        List<String > listId2 = new ArrayList<>();
       /* for (EngineeringDirectors extractDirectors : dirExtra) {

            if (!dirApply.contains(extractDirectors)){
                listId.add(extractDirectors.getItemID());
            }
        }

        for (EngineeringDirectors directors : dirApply) {
            if (!dirExtra.contains(directors)){
                listId2.add(directors.getItemID());
            }
        }*/
        log.error("listId:[{}]",listId);
        log.error("listId:[{}]",listId);
        log.error("listIdSize:[{}]",listId.size());
        log.error("listId2Size:[{}]",listId2.size());


      /* baseInfoExtra.removeAll(baseInfoApply);


        if (!CollectionUtils.isEmpty(baseInfoExtra)){
            ExtractBaseInfo extractBaseInfo1 = baseInfoExtra.get(0);
            log.error("size:[{}]",baseInfoExtra.size());
            String id="";
            for (ExtractBaseInfo extractBaseInfo : baseInfoExtra) {
                id=id+";"+extractBaseInfo.getId();
            }
            log.error("id:[{}]",id);
        }*/
     /*   VersionApply.removeAll(VersionExtra);
        if (!CollectionUtils.isEmpty(VersionApply)){
            log.error("size:[{}]",VersionApply.size());
            String id="";
            for (ExtractEngineeringVersions versions : VersionApply) {
                id=id+";"+versions.getItemID();
            }
            log.error("id:[{}]",id);
        }*/

       /* picApply.removeAll(picExtra);
        if (!CollectionUtils.isEmpty(picApply)){
            log.error("size:[{}]",picApply.size());
            String id="";
            for (ExtractPicInfo pic : picApply) {
                id=id+";"+pic.getId();
            }
            log.error("id:[{}]",id);
        }*/

    }

    @XxlJob("engineeringLinkInfo")
    public void engineeringLinkInfo() throws Exception {

        List<EngineeringLinkInfo> infoList = secondaryMapper.getEngineeringLinkInfo();

      /*  List<EngineeringBaseInfo> baseInfo = secondaryMapper.getCityAndProJNumByEngBaseInfo();

        List<EngineeringLinkInfo> infoList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(linkInfo)&&!CollectionUtils.isEmpty(baseInfo)){

            List<EngineeringLinkInfo> collect = linkInfo.stream().filter(x ->
                    baseInfo.stream().anyMatch(y -> StringUtils.equals(String.valueOf(x.getProjectId()), y.getId()))).collect(Collectors.toList());


            infoList = collect.stream().filter(s -> s.getSolutionID()!=0l && s.getLandID()!=0l

                    || s.getLandID()==0l && s.getSolutionID()!=0l).collect(Collectors.toList());
        }*/

        List<EngineeringLinkInfo> oldLinkInfo = secondaryMapper.getExtractLinkInfo();

        List<EngineeringLinkInfo> copyLinkInfoList = new ArrayList<>(oldLinkInfo);
        copyLinkInfoList.removeAll(infoList);

        for (EngineeringLinkInfo info : copyLinkInfoList) {
            info.setState("0");
            secondaryMapper.updateLinkInfo(info);
        }

        infoList.removeAll(oldLinkInfo);
        if (!CollectionUtils.isEmpty(oldLinkInfo) && !CollectionUtils.isEmpty(infoList)) {
            Set<String> itemIdList = oldLinkInfo.stream()
                    .map(EngineeringLinkInfo::getId)
                    .collect(Collectors.toSet());

            // 过滤
            List<EngineeringLinkInfo> updateList = infoList.stream()
                    .filter(s -> itemIdList.contains(s.getId()))
                    .collect(Collectors.toList());

            if (!CollectionUtils.isEmpty(updateList)) {
                for (EngineeringLinkInfo versions : updateList) {
                    secondaryMapper.updateLinkInfo(versions);
                }
            }
            infoList.removeAll(updateList);
        }
        if (!CollectionUtils.isEmpty(infoList)) {
            infoList.forEach(s -> {
                if ("".equals(s.getLandID())) {
                    s.setLandID(null);
                }if ("".equals(s.getSolutionID())){
                    s.setSolutionID(null);
                }
            });
            // 批次大小
            int batchSize = 100;

            // 计算需要多少个批次
            int totalBatches = (int) Math.ceil((double) infoList.size() / batchSize);

            for (int i = 0; i < totalBatches; i++) {
                // 计算当前批次的起始和结束索引
                int start = i * batchSize;
                int end = Math.min(start + batchSize, infoList.size());

                // 获取当前批次的数据
                List<EngineeringLinkInfo> subList = infoList.subList(start, end);

                // 执行当前批次的插入操作
                secondaryMapper.addExtractLinkInfo(subList);
            }
        }
    }


    @XxlJob("engineerPicInfo")
    public void engineerPicInfo() throws Exception {

        List<EngineeringBaseInfo> baseInfo = secondaryMapper.getCityAndProJNumByEngBaseInfo();

        //只取非 已完工的
        List<EngineeringBaseInfo> baseInfoList = baseInfo.parallelStream().filter(s -> !StringUtils.equals(s.getProjectPhase(), "已完工")).collect(Collectors.toList());


        List<EngineeringPicInfo> picInfoList = secondaryMapper.getPicInfo();


        Set<ProjectVersions> version = secondaryMapper.getVersion();

        // 找出最新版
        Map<String, ProjectVersions> latestVersions = new HashMap<>();
        for (ProjectVersions versions : version) {
            String key = versions.getCity() + "_" + versions.getProjectNumber();
            if (!latestVersions.containsKey(key) ||
                    isNewerVersion(versions, latestVersions.get(key))) {
                latestVersions.put(key, versions);
            }
        }
        List<ProjectVersions> projectVersions = new ArrayList<>(latestVersions.values());


        Set<ProjectVersions> filterList = projectVersions.parallelStream().filter(s -> s.getDistrictMap()!=null
                &&s.getDistrictMap().length() >0).collect(Collectors.toSet());

        //这里是从version表里找出的图片子表Engineering_PicInfo数据
        Set<EngineeringPicInfo> collectVersionList = baseInfoList.parallelStream()
                .flatMap(a -> filterList.parallelStream()
                        .filter(b -> a.getCity().equals(b.getCity()) && a.getProjectNumber().equals(b.getProjectNumber()))
                        .map(b -> new EngineeringPicInfo(String.valueOf(100000000 + Integer.valueOf(a.getId())), a.getId(), "1", "工程项目图", "扫描图片.jpg", b.getDistrictMap())))
                .collect(Collectors.toSet());

        //人工录入的+version提取的
        collectVersionList.addAll(picInfoList);

        Set<EngineeringPicInfo> oldPicInfo = secondaryMapper.getExtractPicInfo();
        Set<EngineeringPicInfo> copyPicInfoList = new HashSet<>(oldPicInfo);
        // copyPicInfoList.removeAll(collectVersionList);
        Set<EngineeringPicInfo> copyCollect = copyPicInfoList.parallelStream()
                .filter(item -> !collectVersionList.contains(item))
                .collect(Collectors.toSet());

        for (EngineeringPicInfo copy : copyCollect) {
            copy.setState("0");
            secondaryMapper.updatePicInfo(copy);
        }

        //  collectVersionList.removeAll(oldPicInfo);
        Set<EngineeringPicInfo> collect = collectVersionList.parallelStream()
                .filter(item -> !oldPicInfo.contains(item))
                .collect(Collectors.toSet());
        Set<EngineeringPicInfo> infoSet = new HashSet<>();
        if (!CollectionUtils.isEmpty(oldPicInfo) && !CollectionUtils.isEmpty(collect)) {

            Set<String> itemIdList = oldPicInfo.stream()
                    .map(EngineeringPicInfo::getId)
                    .collect(Collectors.toSet());

            // 过滤
            List<EngineeringPicInfo> updateList = collect.stream()
                    .filter(s -> itemIdList.contains(s.getId()))
                    .collect(Collectors.toList());

            if (!CollectionUtils.isEmpty(updateList)) {
                for (EngineeringPicInfo versions : updateList) {
                    secondaryMapper.updatePicInfo(versions);
                }
            }
            //   collectVersionList.removeAll(updateList);
            infoSet = collect.parallelStream()
                    .filter(item -> !updateList.contains(item))
                    .collect(Collectors.toSet());
        }
        if (!CollectionUtils.isEmpty(infoSet)) {
            // 批次大小
            int batchSize = 100;

            // 计算需要多少个批次
            int totalBatches = (int) Math.ceil((double) infoSet.size() / batchSize);

            for (int i = 0; i < totalBatches; i++) {
                // 计算当前批次的起始和结束索引
                int start = i * batchSize;
                int end = Math.min(start + batchSize, infoSet.size());

                // 获取当前批次的数据
                List<EngineeringPicInfo> list = new ArrayList<>(infoSet);
                List<EngineeringPicInfo> subList = list.subList(start, end);

                // 执行当前批次的插入操作
                secondaryMapper.addExtractPinInfo(subList);
            }
        }
    }


    @XxlJob("engineerDirectors")
    public void engineerDirectors() throws Exception {
        Set<EngineeringDirectors> allProjectDirectors = secondaryMapper.getAllProjectDirectors();
        Set<EngineeringDirectors> oldDirectors = secondaryMapper.getExtractDirectors();
        Set<ExtractBaseInfo> baseInfo = secondaryMapper.getCityAndNumByExtractBaseInfo();
        Set<ProjectVersions> version = secondaryMapper.getVersion();


        Map<String, List<ProjectVersions>> groupVersionList = version.stream()
                .collect(Collectors.groupingBy(
                        s -> s.getCity() + ":" + s.getProjectNumber(), // 作为键的City:ProjectNumber字符串
                        Collectors.toList()
                ));

        List<Directors> collect = baseInfo.parallelStream()
                .flatMap(info -> {
                    String key = info.getCity() + ":" + info.getProjectNumber();
                    if (groupVersionList.containsKey(key)) {
                        return groupVersionList.get(key).parallelStream()
                                .map(projectVersions -> {
                                    Directors directors = new Directors();
                                    directors.setProjectID(info.getId()); //
                                    directors.setProjectId(projectVersions.getProjectID());
                                    directors.setCity(info.getCity());
                                    directors.setProjectNumber(info.getProjectNumber());
                                    return directors;
                                });
                    }
                    return Stream.empty(); // 如果没有对应的key，则返回空流
                })
                .collect(Collectors.toList());


        // 使用Map来根据City和ProjectNumber分组
        Map<String, List<Directors>> groupedList = collect.stream()
                .collect(Collectors.groupingBy(
                        s -> s.getCity() + ":" + s.getProjectNumber(), // 作为键的City:ProjectNumber字符串
                        Collectors.toList() // 收集具有相同键的用户到列表中
                ));

        Map<String, List<EngineeringDirectors>> groupedDirList = allProjectDirectors.stream()
                .collect(Collectors.groupingBy(
                        s -> s.getProjectId(),
                        Collectors.toList()
                ));




        Set<EngineeringDirectors> directorList = new HashSet<>();
        for (List<Directors> value : groupedList.values()) {
            Set<EngineeringDirectors> newDirectors = new HashSet<>();
            for (Directors directors : value) {
                if (groupedDirList.containsKey(directors.getProjectId())) {

                    List<EngineeringDirectors> list = groupedDirList.get(directors.getProjectId());
                    for (EngineeringDirectors engineeringDirectors : list) {
                        engineeringDirectors.setProjectID(directors.getProjectID());
                        engineeringDirectors.setProjectId(null);
                    }
                    newDirectors.addAll(list);
                }
            }

       /*     Set<EngineeringDirectors> newDirectors = value.parallelStream()
                    .flatMap(a -> allProjectDirectors.parallelStream()
                            .filter(b -> a.getProjectId().equals(b.getProjectId()))
                            .map(b -> new EngineeringDirectors(b.getItemID(), a.getProjectID(), b.getJobType(), b.getContractorUnit(), b.getEnterpriseNature()
                                    , b.getName(), b.getDepartment(), b.getPost(), b.getPhone(), b.getRegisterAddress(), b.getRemarks(),"1")))
                    .collect(Collectors.toSet());*/

            //此时都在同一项目下,找出newDirectors 中重复的数据 ,去重
            if (newDirectors.size() > 1) {

                Map<String, List<EngineeringDirectors>> grouped = newDirectors.parallelStream()
                        .collect(Collectors.groupingBy(
                                ed -> ed.getJobType() + "|" + ed.getContractorUnit() + "|" + ed.getName() + "|" + ed.getPhone()
                        ));

                Map<String, EngineeringDirectors> merged = new HashMap<>();

                for (Map.Entry<String, List<EngineeringDirectors>> entry : grouped.entrySet()) {
                    String key = entry.getKey();
                    List<EngineeringDirectors> group = entry.getValue();

                    // 假设第一个元素是有效的起点 ...任何起点都无所谓
                    EngineeringDirectors mergedEd = group.get(0);

                    // 遍历组中的其他元素来合并字段
                    for (int i = 1; i < group.size(); i++) {
                        EngineeringDirectors current = group.get(i);

                        // 这里只处理itemID和projectID作为示例
                        // 使用null-safe的比较和赋值
                        if (current.getItemID().compareTo(mergedEd.getItemID()) > 0) {
                            mergedEd.setItemID(current.getItemID());
                        }
                        if (current.getEnterpriseNature() != null && (mergedEd.getEnterpriseNature() == null || current.getEnterpriseNature().compareTo(mergedEd.getEnterpriseNature()) > 0)) {
                            mergedEd.setEnterpriseNature(current.getEnterpriseNature());
                        }

                        if (current.getDepartment() != null && (mergedEd.getDepartment() == null || current.getDepartment().compareTo(mergedEd.getDepartment()) > 0)) {
                            mergedEd.setDepartment(current.getDepartment());
                        }

                        if (current.getPost() != null && (mergedEd.getPost() == null || current.getPost().compareTo(mergedEd.getPost()) > 0)) {
                            mergedEd.setPost(current.getPost());
                        }

                        if (current.getRegisterAddress() != null && (mergedEd.getRegisterAddress() == null || current.getRegisterAddress().compareTo(mergedEd.getRegisterAddress()) > 0)) {
                            mergedEd.setRegisterAddress(current.getRegisterAddress());
                        }

                        if (current.getRemarks() != null && (mergedEd.getRemarks() == null || current.getRemarks().compareTo(mergedEd.getRemarks()) > 0)) {
                            mergedEd.setRemarks(current.getRemarks());
                        }
                        // 对其他字段重复上述逻辑
                    }

                    merged.put(key, mergedEd);
                }
                Set<EngineeringDirectors> filteredList = new HashSet<>(merged.values());
                directorList.addAll(filteredList);
            } else  if (newDirectors.size()==1){
                directorList.addAll(newDirectors);
            }
        }
        //Collections.sort(directorList, (u1, u2) -> Integer.compare(Integer.valueOf(u1.getItemID()), Integer.valueOf(u2.getItemID())));

        Set<EngineeringDirectors> copyDirectors = new HashSet<>(oldDirectors);
        //    copyDirectors.removeAll(directorList);

        Set<EngineeringDirectors> collectList = copyDirectors.parallelStream()
                .filter(item -> !directorList.contains(item))
                .collect(Collectors.toSet());

        for (EngineeringDirectors copyDirector : collectList) {
            copyDirector.setState("0");
            secondaryMapper.updateDirectors(copyDirector);
        }

        //  directorList.removeAll(oldDirectors);
        Set<EngineeringDirectors> collectDirector = directorList.parallelStream()
                .filter(item -> !oldDirectors.contains(item))
                .collect(Collectors.toSet());
        //使用Set  ,避免双重遍历
        Set<EngineeringDirectors> directorsSet = new HashSet<>();
        if (!CollectionUtils.isEmpty(oldDirectors) && !CollectionUtils.isEmpty(collectDirector)) {

            Set<String> itemIdList = oldDirectors.parallelStream()
                    .map(EngineeringDirectors::getItemID)
                    .collect(Collectors.toSet());

            // 过滤
            Set<EngineeringDirectors> updateList = collectDirector.stream()
                    .filter(s -> itemIdList.contains(s.getItemID()))
                    .collect(Collectors.toSet());

            if (!CollectionUtils.isEmpty(updateList)) {
                for (EngineeringDirectors versions : updateList) {
                    secondaryMapper.updateDirectors(versions);
                }
            }
            directorsSet = collectDirector.parallelStream()
                    .filter(item -> !updateList.contains(item))
                    .collect(Collectors.toSet());
            //  directorList.removeAll(updateList);
        }


        //去除重复的 ,剩下的认为是需要新增
        //     directorList.removeAll(oldDirectors);
        if (!CollectionUtils.isEmpty(directorsSet)) {
            // 批次大小
            int batchSize = 100;

            // 计算需要多少个批次
            int totalBatches = (int) Math.ceil((double) directorsSet.size() / batchSize);

            for (int i = 0; i < totalBatches; i++) {
                // 计算当前批次的起始和结束索引
                int start = i * batchSize;
                int end = Math.min(start + batchSize, directorsSet.size());

                // 获取当前批次的数据
                List<EngineeringDirectors> list = new ArrayList<>(directorsSet);
                List<EngineeringDirectors> subList = list.subList(start, end);

                // 执行当前批次的插入操作
                secondaryMapper.addExtractDirectorList(subList);
            }
        }

    }

    @XxlJob("engineerVersion")
    public void engineerVersion() throws Exception {

        // List<EngineeringBaseInfo> baseInfoList = secondaryMapper.getCityAndProJNumByEngBaseInfo();
        Set<ExtractBaseInfo> baseInfoList = secondaryMapper.getCityAndNumByExtractBaseInfo();

        List<ExtractEngineeringVersions> versionsList = secondaryMapper.getEngineeringVersions();

        //在     versionsList 中取出和  baseInfoList中city和num相等的数据 ,并且调整 baseInfoList 的id

        Set<ExtractEngineeringVersions> matchingVersions = baseInfoList.parallelStream().flatMap(a -> versionsList.parallelStream().filter(b -> a.getCity().equals(b.getCity()) && a.getProjectNumber().equals(b.getProjectNumber())).map(
                b -> new ExtractEngineeringVersions(b.getItemID(), b.getProjectNumber(), a.getId(), b.getReleaseTime(), b.getVersion(), b.getRemarks(), b.getProjectPhase(), b.getProjectApproval(), b.getProjectDesign(), b.getEquipmentInstallation(), b.getEngineeringSubcontracting(), b.getEngineeringStatus(), "1")
        )).collect(Collectors.toSet());


        Set<ExtractEngineeringVersions>   collectList = new HashSet<>();
        if (!CollectionUtils.isEmpty(matchingVersions)) {
            Set<ExtractEngineeringVersions> oldExtractEngineeringVersions = secondaryMapper.getExtractEngineeringVersions();

            Set<ExtractEngineeringVersions> copiedList = new HashSet<>(oldExtractEngineeringVersions);


            //剩余的是 version表里删除了 ,但是ExtractEngineeringVersions 表里还在的数据 ,也应该state=0 (有一部分是更新操作,这里把state置0 ,下面逻辑代码会改回)
            Set<ExtractEngineeringVersions> versionsSet = copiedList.parallelStream()
                    .filter(item -> !matchingVersions.contains(item))
                    .collect(Collectors.toSet());

            //     copiedList.removeAll(matchingVersions);
            if (!CollectionUtils.isEmpty(versionsSet)) {

                for (ExtractEngineeringVersions oldExtractEngineeringVersion : versionsSet) {
                    oldExtractEngineeringVersion.setState("0");
                    secondaryMapper.updateExtractVersionList(oldExtractEngineeringVersion);
                }
            }


            //去除掉重复元素.

            //matchingVersions.removeAll(oldExtractEngineeringVersions);
            Set<ExtractEngineeringVersions> collect = matchingVersions.parallelStream()
                    .filter(item -> !oldExtractEngineeringVersions.contains(item))
                    .collect(Collectors.toSet());

            //查找 matchingVersions  和oldExtractEngineeringVersions 中 , item相同的数据 ,
            // 这批数据,认为是需要update的  (考虑project_version表可能会认为的update ,所以extract_engineering_versions也同步更新)

            //使用Set  ,避免双重遍历
            if (!CollectionUtils.isEmpty(oldExtractEngineeringVersions) && !CollectionUtils.isEmpty(collect)) {

                Set<String> itemIdList = oldExtractEngineeringVersions.stream()
                        .map(ExtractEngineeringVersions::getItemID)
                        .collect(Collectors.toSet());

                // 过滤
                List<ExtractEngineeringVersions> updateList = collect.parallelStream()
                        .filter(s -> itemIdList.contains(s.getItemID()))
                        .collect(Collectors.toList());

                //理论上数据极少 ,所以不考虑效率 .实际上考虑效率可能也用for+sql .
                if (!CollectionUtils.isEmpty(updateList)) {
                    for (ExtractEngineeringVersions versions : updateList) {
                        secondaryMapper.updateExtractVersionList(versions);
                    }
                }

                //此时剩余的数据 认为是需要新增.
                collectList = collect.parallelStream()
                        .filter(item -> !updateList.contains(item))
                        .collect(Collectors.toSet());

                //  matchingVersions.removeAll(updateList);


            }
        }


        if (!CollectionUtils.isEmpty(collectList)) {
            // 批次大小
            int batchSize = 100;

            // 计算需要多少个批次
            int totalBatches = (int) Math.ceil((double) collectList.size() / batchSize);

            for (int i = 0; i < totalBatches; i++) {
                // 计算当前批次的起始和结束索引
                int start = i * batchSize;
                int end = Math.min(start + batchSize, collectList.size());

                // 获取当前批次的数据
                List<ExtractEngineeringVersions> list = new ArrayList<>(collectList);
                List<ExtractEngineeringVersions> subList = list.subList(start, end);

                // 执行当前批次的插入操作
                secondaryMapper.addExtractVersionList(subList);
            }
        }

    }


    /**
     * 工程项目表处理逻辑
     *
     * @throws Exception
     */
    @XxlJob("engineerBaseInfo")
    public void engineerBaseInfo() throws Exception {
        HashSet<ProjectVersions> versionsList = secondaryMapper.selectVersion();

        // 使用Map来存储每个项目的最新版本，key为唯一标识（城市+项目编号）
        Map<String, ProjectVersions> latestVersions = new HashMap<>();

        for (ProjectVersions versions : versionsList) {
            String key = versions.getCity() + "_" + versions.getProjectNumber();

            if (!latestVersions.containsKey(key) ||
                    isNewerVersion(versions, latestVersions.get(key))) {
                latestVersions.put(key, versions);
            }
        }

        //原始扫描数据 ,放入Map
        List<ProjectVersions> projectVersions = new ArrayList<>(latestVersions.values());
        Map<String, ProjectVersions> versionList = projectVersions.stream()
                .collect(Collectors.toMap(ProjectVersions::getItemID, Function.identity()));

        //人工录入数据
        HashSet<EngineeringBaseInfo> basePerson = secondaryMapper.selectEngineeringBaseInfo();

        Set<EngineeringBaseInfo> completeList = basePerson.parallelStream().filter(s -> StringUtils.equals(s.getProjectPhase(), "已完工")).collect(Collectors.toSet());

        Set<ExtractBaseInfo> extractList = new HashSet<>();
        for (EngineeringBaseInfo baseInfo : completeList) {
            ExtractBaseInfo extractBaseInfo = new ExtractBaseInfo();
            BeanUtils.copyProperties(baseInfo,extractBaseInfo);
            extractList.add(extractBaseInfo);
        }

        //剩下的都是未完工的 ,去version表取数据 ,以version表为主
        //   basePerson.removeAll(completeList);
        Set<EngineeringBaseInfo> collect = basePerson.parallelStream()
                .filter(item -> !completeList.contains(item))
                .collect(Collectors.toSet());
        //获取全部的应用表数据
        Set<ExtractBaseInfo> oldExtract = secondaryMapper.selectExtractAll();
        //复制一份
        Set<ExtractBaseInfo> copiedList = new HashSet<>(oldExtract);


        //遍历人工录入数据 ,查找人工和原始数据重复部分取值.
        for (EngineeringBaseInfo person : collect) {

            if (versionList.containsKey(person.getVersionItemID())) {
                ProjectVersions versions = versionList.get(person.getVersionItemID());
                //获得拼合数据
                ExtractBaseInfo extract = new ExtractBaseInfo();
                BeanUtils.copyProperties(versions,extract);
                extract.setCity(person.getCity());
                extract.setId(person.getId());
                extract.setProjectNumber(person.getProjectNumber());
                extract.setReleaseTime(person.getReleaseTime());
                extractList.add(extract);
            }else {
                ExtractBaseInfo baseInfo = new ExtractBaseInfo();
                baseInfo.setState("1");
                baseInfo.setId(person.getId());
                baseInfo.setCity(person.getCity());
                baseInfo.setProjectNumber(person.getProjectNumber());
                baseInfo.setReleaseTime(person.getReleaseTime());
                extractList.add(baseInfo);
            }
        }

        //extractList 中数据已经被整理 ,但也需要考虑和应用表数据重复问题 .

        //extractList  和oldExtract中 ,找出相同的项目 ,认为这些项目 1 :可能并没有发生变动 ,无需处理 2: 可能需要update
        Set<ExtractBaseInfo> updateExtractList = extractList.parallelStream()
                .filter(x -> oldExtract.parallelStream().anyMatch(y ->
                        x.getCity().equals(y.getCity()) &&
                                x.getProjectNumber().equals(y.getProjectNumber())))
                .collect(Collectors.toSet());


        //这批数据认为库里已有的,比现在查出来的多了 (认为是删除了 ,或者是更新了,这里统一置0,被误操作的更新的数据,下面逻辑代码会还原)
        Set<ExtractBaseInfo> copiedCollect = copiedList.parallelStream()
                .filter(item -> !updateExtractList.contains(item))
                .collect(Collectors.toSet());
        if (!CollectionUtils.isEmpty(copiedCollect)) {
            for (ExtractBaseInfo extractBaseInfo : copiedCollect) {
                extractBaseInfo.setState("0");
                secondaryMapper.updateExtractList(extractBaseInfo);
            }
        }


        Set<ExtractBaseInfo> updateCollect = updateExtractList.parallelStream()
                .filter(item -> !oldExtract.contains(item))
                .collect(Collectors.toSet());
        if (!CollectionUtils.isEmpty(updateCollect)) {
            for (ExtractBaseInfo extractBaseInfo : updateCollect) {
                secondaryMapper.updateExtractList(extractBaseInfo);
            }
        }


        Set<ExtractBaseInfo> collectList = extractList.parallelStream()
                .filter(item -> !oldExtract.contains(item) && !updateExtractList.contains(item)).collect(Collectors.toSet());


        //暂时不考虑 : versions表中有数据 ,但是人工录入表里没有数据的 情况 .这批数据 ,即便是满足要求,也暂时不入库
        if (!CollectionUtils.isEmpty(collectList)) {
            // 批次大小
            int batchSize = 100;

            // 计算需要多少个批次
            int totalBatches = (int) Math.ceil((double) collectList.size() / batchSize);

            for (int i = 0; i < totalBatches; i++) {
                // 计算当前批次的起始和结束索引
                int start = i * batchSize;
                int end = Math.min(start + batchSize, collectList.size());

                // 获取当前批次的数据
                List<ExtractBaseInfo> list = new ArrayList<>(collectList);
                List<ExtractBaseInfo> subList = list.subList(start, end);

                // 执行当前批次的插入操作
                secondaryMapper.insertExtractList(subList);

            }
        }


    }

    /**
     * 捏合原始项目
     * @throws Exception
     */
    @XxlJob("combinEngineerBaseInfo")
    public void combinEngineerBaseInfo() throws Exception{
        HashSet<ProjectVersions> versionsList = secondaryMapper.selectVersion();

        // 使用Map来存储每个项目的最新版本，key为唯一标识（城市+项目编号）
        Map<String, ProjectVersions> latestVersions = new HashMap<>();

        for (ProjectVersions versions : versionsList) {
            if (!StringUtils.isEmpty(versions.getCity())){
                String key = versions.getCity() + "_" + versions.getProjectNumber();

                if (!latestVersions.containsKey(key) ||
                        isNewerVersion(versions, latestVersions.get(key))) {
                    latestVersions.put(key, versions);
                }
            }

        }
        //人工录入数据
        HashSet<EngineeringBaseInfo> basePerson = secondaryMapper.getCityandNumByEngineeringBaseInfo();


        for (EngineeringBaseInfo person : basePerson) {
            String key = person.getCity() + "_" + person.getProjectNumber();
            if (latestVersions.containsKey(key)) {
                ProjectVersions versions = latestVersions.get(key);
                if (!versions.getVersionRank().equals(person.getVersionRank()) || !versions.getReleaseTime().equals(person.getReleaseTime()) || !versions.getItemID().equals(person.getVersionItemID())) {
                    person.setVersionItemID(versions.getItemID());
                    person.setReleaseTime(versions.getReleaseTime());
                    person.setVersionRank(versions.getVersionRank());
                    secondaryMapper.updateEngineer(person);
                }
                latestVersions.remove(key);
            }
        }


        //剩余的项目都是需要插入的
        List<ProjectVersions> projectVersions = new ArrayList<>(latestVersions.values());
        if (!CollectionUtils.isEmpty(projectVersions)) {
            // 批次大小
            int batchSize = 100;

            // 计算需要多少个批次
            int totalBatches = (int) Math.ceil((double) projectVersions.size() / batchSize);

            for (int i = 0; i < totalBatches; i++) {
                // 计算当前批次的起始和结束索引
                int start = i * batchSize;
                int end = Math.min(start + batchSize, projectVersions.size());

                // 获取当前批次的数据
                List<ProjectVersions> subList = projectVersions.subList(start, end);

                // 执行当前批次的插入操作
                secondaryMapper.insertEngineerBaseInfo(subList);

            }
        }
    }

    // 更新的比较逻辑，考虑version_rank可能是非数字的情况
    private static boolean isNewerVersion(ProjectVersions a, ProjectVersions b) {
        int timeCompare = b.getReleaseTime().compareTo(a.getReleaseTime());

        if (timeCompare != 0) {
            // 直接根据时间戳比较
            return timeCompare < 0;
        } else {
            // 时间戳相同，比较version_rank
            boolean isANum = isNumeric(a.getVersionRank());
            boolean isBNum = isNumeric(b.getVersionRank());

            if (isANum && isBNum) {
                // 都是数字时，倒序比较version_rank
                return Double.parseDouble(a.getVersionRank()) > Double.parseDouble(b.getVersionRank());
            } else if (!isANum && !isBNum) {
                // 都是非数字，认为一样新，保持原有顺序（此处逻辑需根据实际需求调整）
                return false; // 或者根据其他规则判定
            } else {
                // 一个数字一个非数字，非数字的认为更新
                return !isANum;
            }
        }
    }

    // 判断字符串是否为数字
    private static boolean isNumeric(String str) {
        try {
            Double.parseDouble(str);
            return true;
        } catch (NumberFormatException e) {
            return false;
        }
    }
}
